//FileName   : rv32i
//Author     : -
//Description: rv32i
//ModifyDate : 2019-5-4
//Company    : -
//Copy right : -
`include "define.v"


module rv32i (
    input               clk,
    input               rst_n,
    input     [31:0]    reqs,
    output              pmem_cs,
    output     [19:0]   pmem_adr,
    input     [31:0]    pmem_rdat,
    input               pmem_ack,
    output reg          dmem_cs,
    output reg          dmem_we,
    output reg [31:0]   dmem_adr,
    output     [31:0]   dmem_wdat,
    input     [31:0]    dmem_rdat,
    input               dmem_ack,
    input               interrupt
);

//internal wire define
wire [31:0]   rfr0;
wire [31:0]   inst_dat;
wire          pmem_we;
wire          de_flush;
wire          ex_flush;
wire [31:0]   inst;
wire [31:0]   pc_next;
wire [31:0]   src1_bypass;
wire [31:0]   src2_bypass;
wire          de_inst_system_ecall_w;
wire          de_inst_system_mret_w;
wire          de_inst_wait_w;
wire          de_inst_auipc_w;
wire          de_inst_lui_w;
wire          de_inst_jalr_w;
wire [29:0]   pc_ind;
wire          de_inst_jal_w;
wire          de_inst_branch_w;
wire          de_inst_cal_w;
wire          de_inst_load_w;
wire          de_inst_store_w;

//internal temp define
reg [31:0]    rfr1;
reg [31:0]    rfr2;
reg [31:0]    rfr3;
reg [31:0]    rfr4;
reg [31:0]    rfr5;
reg [31:0]    rfr6;
reg [31:0]    rfr7;
reg [31:0]    rfr8;
reg [31:0]    rfr9;
reg [31:0]    rfr10;
reg [31:0]    rfr11;
reg [31:0]    rfr12;
reg [31:0]    rfr13;
reg [31:0]    rfr14;
reg [31:0]    rfr15;
reg [31:0]    rfr16;
reg [31:0]    rfr17;
reg [31:0]    rfr18;
reg [31:0]    rfr19;
reg [31:0]    rfr20;
reg [31:0]    rfr21;
reg [31:0]    rfr22;
reg [31:0]    rfr23;
reg [31:0]    rfr24;
reg [31:0]    rfr25;
reg [31:0]    rfr26;
reg [31:0]    rfr27;
reg [31:0]    rfr28;
reg [31:0]    rfr29;
reg [31:0]    rfr30;
reg [31:0]    rfr31;
reg [31:0]    pc_r;
reg [4:0]     src1_adr;
reg [4:0]     de_dest_adr;
reg [4:0]     dest_adr;
reg           reset;
reg [2:0]     op4;
reg           de_inst_system_ecall;
reg           inst_system_ecall;
reg           de_inst_system_mret;
reg           inst_system_mret;
reg [31:0]    mepc;
reg           de_inst_wait;
reg           inst_wait;
reg           reqs_v;
reg [31:0]    de_pc;
reg [31:0]    ex_pc;
reg [19:0]    de_imm0;
reg           de_inst_auipc;
reg           inst_auipc;
reg [31:0]    pc_auipc;
reg [19:0]    imm0;
reg           de_inst_lui;
reg           inst_lui;
reg [31:0]    src1;
reg [11:0]    de_imm1;
reg [11:0]    imm1;
reg           de_inst_jalr;
reg           inst_jalr;
reg [19:0]    de_label0;
reg           de_inst_jal;
reg           inst_jal;
reg [31:0]    src2;
reg [11:0]    de_label1;
reg [2:0]     de_bop;
reg [2:0]     bop;
reg           de_inst_branch;
reg           inst_branch;
reg [11:0]    src2_adr;
reg           de_inst_alu0_5;
reg [3:0]     de_aluop;
reg [3:0]     aluop;
reg           de_inst_cal;
reg           inst_cal;
reg [2:0]     de_mtype;
reg [2:0]     mtype;
reg [2:0]     wb_mtype;
reg           de_inst_load;
reg           inst_load;
reg           wb_inst_load;
reg [4:0]     wb_dest_adr;
reg [11:0]    de_imm2;
reg [11:0]    imm2;
reg           de_inst_store;
reg           inst_store;
reg           interrupt_d;
reg           interrupt_p;
reg           de_interrupt;
reg           ex_interrupt;
reg           taken;
reg [31:0]    pc;
reg [4:0]     rfr_wid;
reg [31:0]    load_data;
reg [31:0]    src2_rfdat;
reg [31:0]    res;
reg           rfr_wr;
reg [31:0]    src1_rfdat;
reg [31:0]    rfr_wdat;
reg [31:0]    de_pc_w;
reg           src1_reqsdat;



//---------------------------------------------
//Function: AA
//---------------------------------------------


//rfr_wr
always @(*)
begin
    if(inst_auipc)
        rfr_wr = 1'b1;
    else if(inst_lui)
        rfr_wr = 1'b1;
    else if(inst_jalr)
        rfr_wr = 1'b1;
    else if(inst_jal)
        rfr_wr = 1'b1;
    else if(inst_cal)
        rfr_wr = 1'b1;
    else if(wb_inst_load)
        rfr_wr = 1'b1;
    else
        rfr_wr = 1'd0;
end


//rfr_wid
always @(*)
begin
    if(inst_auipc)
        rfr_wid = dest_adr;
    else if(inst_lui)
        rfr_wid = dest_adr;
    else if(inst_jalr)
        rfr_wid = dest_adr;
    else if(inst_jal)
        rfr_wid = dest_adr;
    else if(inst_cal)
        rfr_wid = dest_adr;
    else if(wb_inst_load)
        rfr_wid = wb_dest_adr;
    else
        rfr_wid = 5'd0;
end


//rfr_wdat
always @(*)
begin
    if(inst_auipc)
        rfr_wdat = pc_auipc;
    else if(inst_lui)
        rfr_wdat = {imm0,12'd0};
    else if(inst_jalr)
        rfr_wdat = pc_r;
    else if(inst_jal)
        rfr_wdat = pc_r;
    else if(inst_cal)
        rfr_wdat = res;
    else if(wb_inst_load)
        rfr_wdat = load_data;
    else
        rfr_wdat = 32'd0;
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr1 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd1))
        rfr1 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr2 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd2))
        rfr2 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr3 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd3))
        rfr3 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr4 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd4))
        rfr4 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr5 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd5))
        rfr5 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr6 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd6))
        rfr6 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr7 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd7))
        rfr7 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr8 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd8))
        rfr8 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr9 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd9))
        rfr9 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr10 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd10))
        rfr10 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr11 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd11))
        rfr11 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr12 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd12))
        rfr12 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr13 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd13))
        rfr13 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr14 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd14))
        rfr14 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr15 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd15))
        rfr15 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr16 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd16))
        rfr16 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr17 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd17))
        rfr17 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr18 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd18))
        rfr18 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr19 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd19))
        rfr19 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr20 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd20))
        rfr20 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr21 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd21))
        rfr21 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr22 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd22))
        rfr22 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr23 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd23))
        rfr23 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr24 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd24))
        rfr24 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr25 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd25))
        rfr25 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr26 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd26))
        rfr26 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr27 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd27))
        rfr27 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr28 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd28))
        rfr28 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr29 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd29))
        rfr29 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr30 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd30))
        rfr30 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr31 <= 32'd0;
    else begin
    if(rfr_wr&(rfr_wid==5'd31))
        rfr31 <= rfr_wdat;
    end
end

assign rfr0 = 32'd0;


//dmem_cs
always @(*)
begin
    if(inst_load)
        dmem_cs = 1'b1;
    else if(inst_store)
        dmem_cs = 1'b1;
    else
        dmem_cs = 1'd0;
end


//dmem_we
always @(*)
begin
    if(inst_load)
        dmem_we = 1'b0;
    else if(inst_store)
        dmem_we = 1'b1;
    else
        dmem_we = 1'd0;
end


//dmem_adr
always @(*)
begin
    if(inst_load)
        dmem_adr = src1+src2;
    else if(inst_store)
        dmem_adr = src1+{{20{imm2[11]}},imm2[11:0]};
    else
        dmem_adr = 32'd0;
end

assign dmem_wdat = src2;

assign pmem_cs = 1'b1;

assign inst_dat = pmem_rdat;

assign pmem_we = 1'b0;

assign pmem_adr = pc[21:2];

assign de_flush = interrupt_p|de_interrupt|de_inst_system_mret|de_inst_system_ecall|de_inst_jalr|de_inst_jal|de_inst_branch|de_inst_load|de_inst_wait;

assign ex_flush = ex_interrupt|inst_system_mret|inst_system_ecall|inst_jalr|inst_jal|(inst_branch&taken)|(inst_wait&(!reqs_v));

assign inst = ex_flush|de_flush?`NOP:inst_dat;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        pc_r <= {`RSTPC};
    else begin
        pc_r <= pc;
    end
end

assign pc_next = pc_r+32'd4;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        src1_adr <= 5'd0;
    else begin
        src1_adr <= inst[`INST_SRC1];
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_dest_adr <= 5'd0;
    else begin
        de_dest_adr <= inst[`INST_DST];
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        dest_adr <= 5'd0;
    else begin
        dest_adr <= de_dest_adr;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        reset <= {1'b1};
    else begin
    if(reset)
        reset <= 1'b0;
    end
end


//pc
always @(*)
begin
    if(reset)
        pc = `RSTPC;
    else if(inst_system_ecall)
        pc = `MTVEC;
    else if(inst_system_mret)
        pc = mepc;
    else if(inst_jalr)
        pc = {pc_ind,2'd0};
    else if(inst_jal|(inst_branch&taken)|inst_wait&(!reqs_v))
        pc = ex_pc;
    else if(ex_interrupt)
        pc = `MTVEC;
    else if(de_flush)
        pc = pc_r;
    else 
        pc = pc_next;
end

assign src1_bypass = wb_inst_load&(src1_adr[4:0]==wb_dest_adr)?load_data:inst_cal&(src1_adr[4:0]==dest_adr)?res:src1_rfdat;


//src1_rfdat
always @(*)
begin
    case(src1_adr[4:0])
        5'd0:
            src1_rfdat = rfr0;
        5'd1:
            src1_rfdat = rfr1;
        5'd2:
            src1_rfdat = rfr2;
        5'd3:
            src1_rfdat = rfr3;
        5'd4:
            src1_rfdat = rfr4;
        5'd5:
            src1_rfdat = rfr5;
        5'd6:
            src1_rfdat = rfr6;
        5'd7:
            src1_rfdat = rfr7;
        5'd8:
            src1_rfdat = rfr8;
        5'd9:
            src1_rfdat = rfr9;
        5'd10:
            src1_rfdat = rfr10;
        5'd11:
            src1_rfdat = rfr11;
        5'd12:
            src1_rfdat = rfr12;
        5'd13:
            src1_rfdat = rfr13;
        5'd14:
            src1_rfdat = rfr14;
        5'd15:
            src1_rfdat = rfr15;
        5'd16:
            src1_rfdat = rfr16;
        5'd17:
            src1_rfdat = rfr17;
        5'd18:
            src1_rfdat = rfr18;
        5'd19:
            src1_rfdat = rfr19;
        5'd20:
            src1_rfdat = rfr20;
        5'd21:
            src1_rfdat = rfr21;
        5'd22:
            src1_rfdat = rfr22;
        5'd23:
            src1_rfdat = rfr23;
        5'd24:
            src1_rfdat = rfr24;
        5'd25:
            src1_rfdat = rfr25;
        5'd26:
            src1_rfdat = rfr26;
        5'd27:
            src1_rfdat = rfr27;
        5'd28:
            src1_rfdat = rfr28;
        5'd29:
            src1_rfdat = rfr29;
        5'd30:
            src1_rfdat = rfr30;
        5'd31:
            src1_rfdat = rfr31;
        default:
            src1_rfdat = 32'd0;
    endcase
end

assign src2_bypass = wb_inst_load&(src2_adr[4:0]==wb_dest_adr)?load_data:inst_cal&(src2_adr[4:0]==dest_adr)?res:src2_rfdat;


//src2_rfdat
always @(*)
begin
    case(src2_adr[4:0])
        5'd0:
            src2_rfdat = rfr0;
        5'd1:
            src2_rfdat = rfr1;
        5'd2:
            src2_rfdat = rfr2;
        5'd3:
            src2_rfdat = rfr3;
        5'd4:
            src2_rfdat = rfr4;
        5'd5:
            src2_rfdat = rfr5;
        5'd6:
            src2_rfdat = rfr6;
        5'd7:
            src2_rfdat = rfr7;
        5'd8:
            src2_rfdat = rfr8;
        5'd9:
            src2_rfdat = rfr9;
        5'd10:
            src2_rfdat = rfr10;
        5'd11:
            src2_rfdat = rfr11;
        5'd12:
            src2_rfdat = rfr12;
        5'd13:
            src2_rfdat = rfr13;
        5'd14:
            src2_rfdat = rfr14;
        5'd15:
            src2_rfdat = rfr15;
        5'd16:
            src2_rfdat = rfr16;
        5'd17:
            src2_rfdat = rfr17;
        5'd18:
            src2_rfdat = rfr18;
        5'd19:
            src2_rfdat = rfr19;
        5'd20:
            src2_rfdat = rfr20;
        5'd21:
            src2_rfdat = rfr21;
        5'd22:
            src2_rfdat = rfr22;
        5'd23:
            src2_rfdat = rfr23;
        5'd24:
            src2_rfdat = rfr24;
        5'd25:
            src2_rfdat = rfr25;
        5'd26:
            src2_rfdat = rfr26;
        5'd27:
            src2_rfdat = rfr27;
        5'd28:
            src2_rfdat = rfr28;
        5'd29:
            src2_rfdat = rfr29;
        5'd30:
            src2_rfdat = rfr30;
        5'd31:
            src2_rfdat = rfr31;
        default:
            src2_rfdat = 32'd0;
    endcase
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        op4 <= 3'd0;
    else begin
    if((inst[`INST_INST]==`INST_SYSTEM) )
        op4 <= inst[`INST_OP4];
    end
end

assign de_inst_system_ecall_w = (inst[`INST_INST]==`INST_SYSTEM)&(inst[`INST_OP4]==`OP4_ECALL);

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_system_ecall <= 1'd0;
    else begin
        de_inst_system_ecall <= de_inst_system_ecall_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_system_ecall <= 1'd0;
    else begin
        inst_system_ecall <= de_inst_system_ecall;
    end
end

assign de_inst_system_mret_w = (inst[`INST_INST]==`INST_SYSTEM)&(inst[`INST_OP4]==`OP4_MRET);

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_system_mret <= 1'd0;
    else begin
        de_inst_system_mret <= de_inst_system_mret_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_system_mret <= 1'd0;
    else begin
        inst_system_mret <= de_inst_system_mret;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        mepc <= 32'd0;
    else begin
    if(inst_system_ecall)
        mepc <= pc_r;
    else if(de_interrupt&inst_system_ecall)
        mepc <= `MTVEC;
    else if(de_interrupt&inst_jalr)
        mepc <= {pc_ind,2'd0};
    else if(de_interrupt&((inst_wait&(!reqs_v))|inst_jal|(inst_branch&taken)))
        mepc <= ex_pc;
    else if(de_interrupt&(!inst_system_mret))
        mepc <= pc_r;
    end
end

assign de_inst_wait_w = inst[`INST_INST]==`INST_WAIT;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_wait <= 1'd0;
    else begin
        de_inst_wait <= de_inst_wait_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_wait <= 1'd0;
    else begin
        inst_wait <= de_inst_wait;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        reqs_v <= 1'd0;
    else begin
        reqs_v <= src1_reqsdat;
    end
end


//src1_reqsdat
always @(*)
begin
    case(src1_adr[4:0])
        5'd0:
            src1_reqsdat = reqs[0];
        5'd1:
            src1_reqsdat = reqs[1];
        5'd2:
            src1_reqsdat = reqs[2];
        5'd3:
            src1_reqsdat = reqs[3];
        5'd4:
            src1_reqsdat = reqs[4];
        5'd5:
            src1_reqsdat = reqs[5];
        5'd6:
            src1_reqsdat = reqs[6];
        5'd7:
            src1_reqsdat = reqs[7];
        5'd8:
            src1_reqsdat = reqs[8];
        5'd9:
            src1_reqsdat = reqs[9];
        5'd10:
            src1_reqsdat = reqs[10];
        5'd11:
            src1_reqsdat = reqs[11];
        5'd12:
            src1_reqsdat = reqs[12];
        5'd13:
            src1_reqsdat = reqs[13];
        5'd14:
            src1_reqsdat = reqs[14];
        5'd15:
            src1_reqsdat = reqs[15];
        5'd16:
            src1_reqsdat = reqs[16];
        5'd17:
            src1_reqsdat = reqs[17];
        5'd18:
            src1_reqsdat = reqs[18];
        5'd19:
            src1_reqsdat = reqs[19];
        5'd20:
            src1_reqsdat = reqs[20];
        5'd21:
            src1_reqsdat = reqs[21];
        5'd22:
            src1_reqsdat = reqs[22];
        5'd23:
            src1_reqsdat = reqs[23];
        5'd24:
            src1_reqsdat = reqs[24];
        5'd25:
            src1_reqsdat = reqs[25];
        5'd26:
            src1_reqsdat = reqs[26];
        5'd27:
            src1_reqsdat = reqs[27];
        5'd28:
            src1_reqsdat = reqs[28];
        5'd29:
            src1_reqsdat = reqs[29];
        5'd30:
            src1_reqsdat = reqs[30];
        5'd31:
            src1_reqsdat = reqs[31];
        default:
            src1_reqsdat = 1'd0;
    endcase
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_pc <= {`RSTPC};
    else begin
    if((inst[`INST_INST]==`INST_WAIT) )
        de_pc <= pc_r;
    else if((inst[`INST_INST]==`INST_AUIPC) )
        de_pc <= pc_r;
    else if((inst[`INST_INST]==`INST_JAL) )
        de_pc <= pc_r;
    else if((inst[`INST_INST]==`INST_BRANCH) )
        de_pc <= pc_r;
    end
end


//de_pc_w
always @(*)
begin
    if(de_inst_wait)
        de_pc_w = de_pc;
    else if(de_inst_jal)
        de_pc_w = de_pc + {{11{de_label0[19]}},de_label0[19:0],1'b0};
    else if(de_inst_branch)
        de_pc_w = de_pc + {{19{de_label1[11]}},de_label1[11:1],2'd0};
    else
        de_pc_w = 32'd0;
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        ex_pc <= {`RSTPC};
    else begin
        ex_pc <= de_pc_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_imm0 <= 20'd0;
    else begin
        de_imm0 <= inst[`INST_IMM0];
    end
end

assign de_inst_auipc_w = inst[`INST_INST]==`INST_AUIPC;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_auipc <= 1'd0;
    else begin
        de_inst_auipc <= de_inst_auipc_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_auipc <= 1'd0;
    else begin
        inst_auipc <= de_inst_auipc;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        pc_auipc <= 32'd0;
    else begin
        pc_auipc <= de_pc+{de_imm0,12'd0};
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        imm0 <= 20'd0;
    else begin
        imm0 <= de_imm0;
    end
end

assign de_inst_lui_w = inst[`INST_INST]==`INST_LUI;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_lui <= 1'd0;
    else begin
        de_inst_lui <= de_inst_lui_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_lui <= 1'd0;
    else begin
        inst_lui <= de_inst_lui;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        src1 <= 32'd0;
    else begin
    if(de_inst_jalr)
        src1 <= src1_bypass;
    else if(de_inst_branch)
        src1 <= src1_bypass;
    else if(de_inst_cal)
        src1 <= src1_bypass;
    else if(de_inst_load)
        src1 <= src1_bypass;
    else if(de_inst_store)
        src1 <= src1_bypass;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_imm1 <= 12'd0;
    else begin
    if((inst[`INST_INST]==`INST_JALR) )
        de_imm1 <= inst[`INST_IMM1];
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        imm1 <= 12'd0;
    else begin
        imm1 <= de_imm1;
    end
end

assign de_inst_jalr_w = inst[`INST_INST]==`INST_JALR;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_jalr <= 1'd0;
    else begin
        de_inst_jalr <= de_inst_jalr_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_jalr <= 1'd0;
    else begin
        inst_jalr <= de_inst_jalr;
    end
end

assign pc_ind = src1[31:2]+{{20{imm1[11]}},imm1[11:2]};

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_label0 <= 20'd0;
    else begin
    if((inst[`INST_INST]==`INST_JAL) )
        de_label0 <= {inst[31],inst[19:12],inst[20],inst[30:21]};
    end
end

assign de_inst_jal_w = inst[`INST_INST]==`INST_JAL;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_jal <= 1'd0;
    else begin
        de_inst_jal <= de_inst_jal_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_jal <= 1'd0;
    else begin
        inst_jal <= de_inst_jal;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        src2 <= 32'd0;
    else begin
    if(de_inst_branch)
        src2 <= src2_bypass;
    else if(de_inst_cal)
        src2 <= de_inst_alu0_5?src2_bypass : {{20{src2_adr[11]}},src2_adr};
    else if(de_inst_load)
        src2 <= {{20{src2_adr[11]}},src2_adr[11:0]};
    else if(de_inst_store)
        src2 <= src2_bypass;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_label1 <= 12'd0;
    else begin
    if((inst[`INST_INST]==`INST_BRANCH) )
        de_label1 <= {inst[31],inst[7],inst[30:25],inst[11:8]};
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_bop <= 3'd0;
    else begin
    if((inst[`INST_INST]==`INST_BRANCH) )
        de_bop <= inst[`INST_OP0];
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        bop <= 3'd0;
    else begin
        bop <= de_bop;
    end
end

assign de_inst_branch_w = inst[`INST_INST]==`INST_BRANCH;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_branch <= 1'd0;
    else begin
        de_inst_branch <= de_inst_branch_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_branch <= 1'd0;
    else begin
        inst_branch <= de_inst_branch;
    end
end


//taken
always @(*)
begin
    case(bop[2:0])
        `BEQ:
            taken = src1 == src2;
        `BNE:
            taken = src1 != src2;
        `BLT:
            taken = $signed(src1) < $signed(src2);
        `BGE:
            taken = $signed(src1) >= $signed(src2);
        `BLTU:
            taken = src1 < src2;
        `BGEU:
            taken = src1 >= src2;
        default:
            taken = 1'd0;
    endcase
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        src2_adr <= 12'd0;
    else begin
    if((inst[`INST_INST]==`INST_CAL)||(inst[`INST_INST]==`INST_CALI) )
        src2_adr <= inst[`INST_INST_5]?inst[`INST_SRC2]:inst[`INST_IMM1];
    else if((inst[`INST_INST]==`INST_LOAD) )
        src2_adr <= inst[`INST_IMM1];
    else 
        src2_adr <= inst[`INST_SRC2];
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_alu0_5 <= 1'd0;
    else begin
    if((inst[`INST_INST]==`INST_CAL)||(inst[`INST_INST]==`INST_CALI) )
        de_inst_alu0_5 <= inst[`INST_INST_5];
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_aluop <= 4'd0;
    else begin
    if((inst[`INST_INST]==`INST_CAL)||(inst[`INST_INST]==`INST_CALI) )
        de_aluop <= {inst[30],inst[`INST_OP0]};
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        aluop <= 4'd0;
    else begin
        aluop <= de_aluop;
    end
end

assign de_inst_cal_w = (inst[`INST_INST]==`INST_CAL)||(inst[`INST_INST]==`INST_CALI);

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_cal <= 1'd0;
    else begin
        de_inst_cal <= de_inst_cal_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_cal <= 1'd0;
    else begin
        inst_cal <= de_inst_cal;
    end
end


//res
always @(*)
begin
    case(aluop[2:0])
        `ADD:
            res = aluop[3]?src1 - src2:src1 + src2;
        `SLL:
            res = src1 << src2[4:0];
        `SLT:
            res = $signed(src1) < $signed(src2);
        `SLTU:
            res = src1 < src2;
        `XOR:
            res = src1 ^ src2;
        `SRL:
            res = aluop[3]?$signed(src1) >>> src2[4:0]:src1 >> src2[4:0];
        `OR:
            res = src1 | src2;
        `AND:
            res = src1 & src2;
        default:
            res = 32'd0;
    endcase
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_mtype <= 3'd0;
    else begin
    if((inst[`INST_INST]==`INST_LOAD) )
        de_mtype <= inst[`INST_OP1];
    else if( inst[`INST_INST]==`INST_STORE )
        de_mtype <= inst[`INST_OP1];
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        mtype <= 3'd0;
    else begin
        mtype <= de_mtype;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        wb_mtype <= 3'd0;
    else begin
        wb_mtype <= mtype;
    end
end

assign de_inst_load_w = inst[`INST_INST]==`INST_LOAD;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_load <= 1'd0;
    else begin
        de_inst_load <= de_inst_load_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_load <= 1'd0;
    else begin
        inst_load <= de_inst_load;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        wb_inst_load <= 1'd0;
    else begin
        wb_inst_load <= inst_load;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        wb_dest_adr <= 5'd0;
    else begin
        wb_dest_adr <= dest_adr;
    end
end


//load_data
always @(*)
begin
    case(wb_mtype[2:0])
        `OP1_H:
            load_data = {{16{dmem_rdat[15]}},dmem_rdat[15:0]};
        `OP1_B:
            load_data = {{24{dmem_rdat[7]}},dmem_rdat[7:0]};
        `OP1_HU:
            load_data = {16'd0,dmem_rdat[15:0]};
        `OP1_BU:
            load_data = {24'd0,dmem_rdat[7:0]};
        default:
            load_data = dmem_rdat;
    endcase
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_imm2 <= 12'd0;
    else begin
    if( inst[`INST_INST]==`INST_STORE )
        de_imm2 <= {inst[31:25],inst[11:7]};
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        imm2 <= 12'd0;
    else begin
        imm2 <= de_imm2;
    end
end

assign de_inst_store_w = inst[`INST_INST]==`INST_STORE;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_store <= 1'd0;
    else begin
        de_inst_store <= de_inst_store_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_store <= 1'd0;
    else begin
        inst_store <= de_inst_store;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        interrupt_d <= 1'd0;
    else begin
        interrupt_d <= interrupt;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        interrupt_p <= 1'd0;
    else begin
        interrupt_p <= !interrupt_d&interrupt;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_interrupt <= 1'd0;
    else begin
        de_interrupt <= interrupt_p;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        ex_interrupt <= 1'd0;
    else begin
        ex_interrupt <= de_interrupt;
    end
end

endmodule
